/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.entityGenerator.base.elements;


import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.inspur.edp.caf.generator.baseInfo.AnnotationInfo;
import com.inspur.edp.caf.generator.baseInfo.AnnotationType;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.property.ClassPropertyGenerator;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspElementDataType;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.generator.entityGenerator.base.DataTypeGeneratorContext;
import com.inspur.edp.cef.generator.overall.Utils;
import com.inspur.edp.cef.spi.jsonser.abstractcefchange.BefDateSerializer;
import com.inspur.edp.cef.spi.jsonser.abstractcefchange.BefDateTimeDeseiralizer;
import com.inspur.edp.cef.spi.jsonser.abstractcefchange.BefDateTimeSerializer;
import com.inspur.edp.cef.spi.jsonser.base.StringUtils;
import lombok.var;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.TypeLiteral;

import java.util.ArrayList;
import java.util.HashMap;

public class AssoPropertyGenerator extends ClassPropertyGenerator {
	private IGspCommonField field;
	private GspAssociation association;
	private DataTypeGeneratorContext dataTypeGenContext;

	public AssoPropertyGenerator(IGspCommonField field, GspAssociation association, DataTypeGeneratorContext dataTypeGenContext) {
		this.field = field;
		this.association = association;
		this.dataTypeGenContext = dataTypeGenContext;
	}

	public IGspCommonField getElement(){
		return field;
	}
	@Override
	public String getPropertyName() {
		return field.getLabelID();
	}

	public String getGetterName(){
		return "get"+getPropertyName();
	}

	public String getSetterName(){
		return "set"+getPropertyName();
	}

	@Override
	protected TypeInfo getPropertyType() {
		return Utils.getRefElementPropertyName(field, association, dataTypeGenContext.getEntityGenContext().getCefGenContext());
	}

	public TypeInfo getType(){
		return getPropertyType();
	}
	@Override
	protected String getFieldName() {
		return AssoFieldGenerator.getFieldName(field);
	}

	@Override
	protected ArrayList<AnnotationInfo> getGetterAttributeList() {
		ArrayList<AnnotationInfo> list = super.getGetterAttributeList();
		if (list == null)
			list = new ArrayList<>();

//		AnnotationInfo propAnnotation = new AnnotationInfo();
//		propAnnotation.setTypeInfo(new TypeInfo(PropertyGetAtrribute.class));
//		propAnnotation.setAnnotationType(AnnotationType.Normal);
//		propAnnotation.getParams().put("propName", ExpressionUtils.getStringLiteral(ast, field.getLabelID()));
//		list.add(propAnnotation);


		if (field.getObjectType() == GspElementObjectType.Enum && !field.getIsUdt()) {
			AnnotationInfo annotationInfo = new AnnotationInfo();
			annotationInfo.setAnnotationType(AnnotationType.Normal);
			TypeInfo typeInfo = new TypeInfo("JsonSerialize");
			typeInfo.setTypePackageName("com.fasterxml.jackson.databind.annotation");
			annotationInfo.setTypeInfo(typeInfo);
			TypeLiteral param = ast.newTypeLiteral();
			param.setType(ast.newSimpleType(ast.newSimpleName("EnumConvertor")));
			addImport("com.inspur.edp.bff.spi.utils.EnumConvertor");
			annotationInfo.getParams().put("using", param);
			list.add(annotationInfo);
		}

		AnnotationInfo annotationInfo = new AnnotationInfo();
		annotationInfo.setAnnotationType(AnnotationType.SingleMember);
		annotationInfo.setTypeInfo(new TypeInfo(JsonProperty.class));
		annotationInfo.setSingleParam(ExpressionUtils.getStringLiteral(
				ast, StringUtils.toCamelCase(getPropertyName())
		));
		list.add(annotationInfo);

		if (!field.getIsUdt() && (field.getMDataType() == GspElementDataType.Date || field.getMDataType() == GspElementDataType.DateTime)) {
			list.add(getBefDateDeserializerAnnoInfo(field.getMDataType()));
		}

		return list;
	}

	@Override
	protected ArrayList<AnnotationInfo> getSetterAttributeList() {
		ArrayList<AnnotationInfo> list = super.getSetterAttributeList();
		if (list == null) {
			list = new ArrayList<>();
		}
		if (!field.getIsUdt() && (field.getMDataType() == GspElementDataType.Date || field.getMDataType() == GspElementDataType.DateTime)) {
			list.add(getBefDateSerializerAnnoInfo(field.getMDataType()));
		}
		return list;
	}

	@Override
	protected ArrayList<Modifier.ModifierKeyword> getGetterAccessModifier() {
		return new ArrayList(java.util.Arrays.asList(new Modifier.ModifierKeyword[]{
				Modifier.ModifierKeyword.PUBLIC_KEYWORD}));
	}

	@Override
	protected ArrayList<Modifier.ModifierKeyword> getSetterAccessModifier() {
		return new ArrayList(java.util.Arrays.asList(new Modifier.ModifierKeyword[]{
				Modifier.ModifierKeyword.PUBLIC_KEYWORD}));
	}

	private AnnotationInfo getBefDateDeserializerAnnoInfo(GspElementDataType dataType) {
		if (dataType != GspElementDataType.Date && dataType != GspElementDataType.DateTime) {
			throw new RuntimeException("仅日期类型可调用此方法");
		}
		AnnotationInfo info = new AnnotationInfo();
		info.setAst(ast);
		info.setAnnotationType(AnnotationType.Normal);

		String deserializerType = BefDateTimeDeseiralizer.class.getName();
		HashMap<String, Expression> map = new HashMap<>();
		TypeLiteral typeLiteral = ast.newTypeLiteral();
		typeLiteral.setType(ast.newSimpleType(ast.newName(deserializerType)));
		map.put("using", typeLiteral);
		info.setParams(map);
		info.setTypeInfo(new TypeInfo(JsonDeserialize.class));

		addImport(deserializerType);
		return info;
	}

	private AnnotationInfo getBefDateSerializerAnnoInfo(GspElementDataType dataType) {
		if (dataType != GspElementDataType.Date && dataType != GspElementDataType.DateTime) {
			throw new RuntimeException("仅日期类型可调用此方法");
		}
		AnnotationInfo info = new AnnotationInfo();
		info.setAst(ast);
		info.setAnnotationType(AnnotationType.Normal);
		String serializerType = "";
		switch (dataType) {
			case Date:
				serializerType = BefDateSerializer.class.getName();
				break;
			case DateTime:
				serializerType = BefDateTimeSerializer.class.getName();
				break;
		}
		HashMap<String, Expression> map = new HashMap<>();
		TypeLiteral typeLiteral = ast.newTypeLiteral();
		typeLiteral.setType(ast.newSimpleType(ast.newName(serializerType)));
		map.put("using", typeLiteral);
		info.setParams(map);
		info.setTypeInfo(new TypeInfo(JsonSerialize.class));

		addImport(serializerType);
		return info;
	}
}
